import { LoaderDataFormat } from './LoaderDataFormat';

/**
 * 加载类
 */
export class Loader
{
    /**
     * 加载文本
     * @param url 路径
     */
    async loadText(url: string, onRequestProgress?: () => void)
    {
        const context: string = await new Promise((resolve, reject) =>
        {
            xmlHttpRequestLoad({
                url, dataFormat: LoaderDataFormat.TEXT, onCompleted: resolve as any, onProgress: onRequestProgress, onError: reject
            });
        });

        return context;
    }

    /**
     * 加载二进制
     * @param url 路径
     */
    async loadBinary(url: string, onRequestProgress?: () => void)
    {
        const context: ArrayBuffer = await new Promise((resolve, reject) =>
        {
            xmlHttpRequestLoad({
                url, dataFormat: LoaderDataFormat.BINARY, onCompleted: resolve as any, onProgress: onRequestProgress, onError: reject
            });
        });

        return context;
    }

    /**
     * 加载图片
     * @param url 路径
     */
    async loadImage(url: string)
    {
        const context: HTMLImageElement = await new Promise((resolve, _reject) =>
        {
            const image = new Image();

            image.crossOrigin = 'Anonymous';
            image.onload = (_event) =>
            {
                resolve(image);
            };
            image.onerror = (_event) =>
            {
                console.error(`Error while trying to load texture: ${url}`);
                //
                image.src = '';
                //
                console.warn(new Error(`${url} 加载失败！`));

                resolve(image);
            };
            image.src = url;
        });

        return context;
    }
}

/**
 * 加载类
 */
export const loader = new Loader();

interface LoadItem
{
    url: string;
    dataFormat: LoaderDataFormat;
    onCompleted?: (content: string | ArrayBuffer) => void;
    onProgress?: (loaded: number, total: number) => void;
    onError?: (ev: Error) => void;
}

/**
 * 使用XMLHttpRequest加载
 * @param url 加载路径
 * @param dataFormat 数据类型
 */
function xmlHttpRequestLoad(loadItem: LoadItem)
{
    const request = new XMLHttpRequest();

    request.open('Get', loadItem.url, true);
    request.setRequestHeader('Access-Control-Allow-Origin', '*');
    request.responseType = loadItem.dataFormat === LoaderDataFormat.BINARY ? 'arraybuffer' : '';
    request.onreadystatechange = onRequestReadystatechange(request, loadItem);
    request.onprogress = onRequestProgress(request, loadItem);
    request.send();
}

/**
 * 请求进度回调
 */
function onRequestProgress(request: XMLHttpRequest, loadItem: LoadItem)
{
    return (event: ProgressEvent) =>
    {
        loadItem.onProgress && loadItem.onProgress(event.loaded, event.total);
    };
}

/**
 * 请求状态变化回调
 */
function onRequestReadystatechange(request: XMLHttpRequest, loadItem: LoadItem)
{
    return (_ev) =>
    {
        if (request.readyState === 4)
        { // 4 = "loaded"
            request.onreadystatechange = null;

            if (request.status >= 200 && request.status < 300)
            {
                const content = loadItem.dataFormat === LoaderDataFormat.TEXT ? request.responseText : request.response;

                loadItem.onCompleted && loadItem.onCompleted(content);
            }
            else
            {
                const err = new Error(`${loadItem.url} 加载失败！`);

                loadItem.onError && loadItem.onError(err);
                loadItem.onCompleted && loadItem.onCompleted(null);
            }
        }
    };
}
